package service

import (
	"context"
	"fmt"
	v1 "gin-vben-admin/api/v1"
	"gin-vben-admin/api/v1/errcode"
	"gin-vben-admin/internal/constant"
	"gin-vben-admin/internal/model"
	"gin-vben-admin/internal/repository"
	"github.com/opdss/go-helper/slices"
	"strings"
)

type SysMenuService interface {
	GetTreeListByPid(ctx context.Context, menuId int64) (treeModels []*model.SysMenu, err error)
	Detail(ctx context.Context, menuId int64) (*model.SysMenu, error)
	Delete(ctx context.Context, menuId int64) (err error)
	CreateMenu(ctx context.Context, req *v1.SysMenuCreateReq) (err error)
	CreateAction(ctx context.Context, req *v1.SysMenuCreateActionReq) error
	UpdateMenu(ctx context.Context, req *v1.SysMenuUpdateReq) (err error)
	UpdateAction(ctx context.Context, req *v1.SysMenuUpdateActionReq) (err error)
}

func NewSysMenuService(service *Service, menuRepo repository.SysMenuRepository) SysMenuService {
	return &sysMenuService{
		menuRepo: menuRepo,
		Service:  service,
	}
}

type sysMenuService struct {
	menuRepo repository.SysMenuRepository
	*Service
}

func (s *sysMenuService) Detail(ctx context.Context, menuId int64) (*model.SysMenu, error) {
	return s.menuRepo.GetById(ctx, menuId)
}

// CreateMenu 添加菜单
func (s *sysMenuService) CreateMenu(ctx context.Context, req *v1.SysMenuCreateReq) (err error) {
	m := model.SysMenu{}
	m.MenuName = req.MenuName
	m.Sort = req.Sort
	m.Status = req.Status
	m.Icon = req.Icon
	m.Path = req.Path
	m.RouteName = req.RouteName
	m.NoCache = req.NoCache
	m.ParentId = req.ParentId
	if req.NoCache == 0 {
		m.NoCache = constant.Yes
	}
	m.Component = req.Component
	m.Visible = req.Visible
	if req.Visible == 0 {
		m.Visible = constant.Yes
	}
	m.IsFrame = req.IsFrame
	if req.IsFrame == 0 {
		m.IsFrame = constant.No
	}
	m.CreateBy = req.AuthId
	m.UpdateBy = req.AuthId
	m.MenuType = constant.MenuTypeMenu
	//顶级菜单
	var pModel *model.SysMenu
	if m.ParentId != 0 {
		pModel, err = s.menuRepo.GetById(ctx, m.ParentId)
		if err != nil || pModel.MenuType == constant.MenuTypeAction {
			return errcode.ErrBadRequest.New("父菜单选择错误")
		}
		m.IdPath = fmt.Sprintf("%s%d/", pModel.IdPath, pModel.MenuId)
	} else {
		m.IdPath = "/0/"
	}
	return s.menuRepo.Create(ctx, &m)
}

// CreateAction 添加操作
func (s *sysMenuService) CreateAction(ctx context.Context, req *v1.SysMenuCreateActionReq) error {
	m := model.SysMenu{}
	m.MenuName = req.MenuName
	m.Sort = req.Sort
	m.Status = req.Status
	m.Permission = req.Permission
	m.ParentId = req.ParentId
	m.CreateBy = req.AuthId
	m.UpdateBy = req.AuthId
	m.MenuType = constant.MenuTypeAction
	//顶级菜单
	pModel, err := s.menuRepo.GetById(ctx, m.ParentId)
	if err != nil || pModel.MenuType == constant.MenuTypeAction {
		return errcode.ErrBadRequest.New("父菜单选择错误")
	}
	m.IdPath = fmt.Sprintf("%s%d/", pModel.IdPath, pModel.MenuId)
	if s.menuRepo.ExistsPermission(ctx, m.Permission, 0) {
		return errcode.ErrBadRequest.New("权限标识已经存在")
	}
	return s.tm.Transaction(ctx, func(ctx context.Context) error {
		err := s.menuRepo.Create(ctx, &m)
		if err != nil {
			return err
		}
		totalId := len(req.ApiIds)
		if totalId > 0 {
			menuApis := make([]*model.SysMenuApi, totalId)
			apiIds := make([]int64, totalId)
			for i, apiId := range req.ApiIds {
				menuApis[i] = &model.SysMenuApi{
					MenuId: m.MenuId,
					ApiId:  apiId,
				}
				apiIds[i] = apiId
			}
			//校验apiid
			apiIds = slices.Unique(apiIds)
			if len(apiIds) != totalId {
				return errcode.ErrBadRequest
			}
			return s.menuRepo.CreateMenuApis(ctx, menuApis)
		}
		return nil
	})
}

// GetTreeListByPid 根据parentId获取子菜单树状结构
func (s *sysMenuService) GetTreeListByPid(ctx context.Context, menuId int64) (treeModels []*model.SysMenu, err error) {
	var menuList []*model.SysMenu
	menuList, err = s.menuRepo.GetListByPid(ctx, menuId)
	if err != nil {
		return
	}
	return s.genTreeList(menuList, menuId), nil
}

func (s *sysMenuService) Delete(ctx context.Context, menuId int64) (err error) {
	if menuId == 0 {
		return errcode.ErrBadRequest
	}
	//事物处理
	return s.tm.Transaction(ctx, func(ctx context.Context) error {
		pTotal, err := s.menuRepo.GetCountByPid(ctx, menuId)
		if err != nil {
			return err
		}
		if pTotal > 0 {
			return errcode.ErrBadRequest.New("请先将其子菜单删除后方能删除此菜单")
		}
		err = s.menuRepo.Delete(ctx, menuId)
		if err != nil {
			return err
		}
		//err = query.Where("menu_id=?", menuId).Delete(&models.SysPermission{})
		//if err != nil {
		//	return err
		//}
		return s.menuRepo.DeleteMenuApi(ctx, menuId)
	})
}

func (s *sysMenuService) UpdateMenu(ctx context.Context, req *v1.SysMenuUpdateReq) (err error) {
	var m *model.SysMenu
	m, err = s.menuRepo.GetById(ctx, req.MenuId)
	if err != nil {
		return
	}
	m.MenuName = req.MenuName
	m.Sort = req.Sort
	m.Status = req.Status
	m.Icon = req.Icon
	m.Path = req.Path
	m.RouteName = req.RouteName
	m.NoCache = req.NoCache
	m.ParentId = req.ParentId
	if req.NoCache == 0 {
		m.NoCache = constant.Yes
	}
	m.Component = req.Component
	m.Visible = req.Visible
	if req.Visible == 0 {
		m.Visible = constant.Yes
	}
	m.IsFrame = req.IsFrame
	if req.IsFrame == 0 {
		m.IsFrame = constant.No
	}
	m.UpdateBy = req.AuthId
	m.MenuType = constant.MenuTypeMenu
	if m.MenuType != constant.MenuTypeMenu {
		return errcode.ErrBadRequest.New("菜单类型错误")
	}
	if m.ParentId == m.MenuId {
		return errcode.ErrBadRequest.New("父菜单选择错误")
	}

	//顶级菜单
	oldS := fmt.Sprintf("%s%d/", m.IdPath, m.MenuId)
	var pModel *model.SysMenu
	if m.ParentId != 0 {
		pModel, err = s.menuRepo.GetById(ctx, m.ParentId)
		if err != nil || pModel.MenuType == constant.MenuTypeAction {
			return errcode.ErrBadRequest.New("父菜单选择错误")
		}
		if strings.Contains(pModel.IdPath, fmt.Sprintf("/%d/", m.MenuId)) {
			return errcode.ErrBadRequestParams.New("父菜单选择错误")
		}
		m.IdPath = fmt.Sprintf("%s%d/", pModel.IdPath, pModel.MenuId)
	} else {
		m.IdPath = "/0/"
	}
	newS := fmt.Sprintf("%s%d/", m.IdPath, m.MenuId)

	m.Permission = ""
	//if model.Path == "" {
	//	return response.ErrInvalidParams.New("路由路径不能为空")
	//}
	//if (model.IsFrame == constant.No || model.ParentId != 0) && model.Component == "" {
	//	return response.ErrInvalidParams.New("组件不能为空")
	//}
	return s.tm.Transaction(ctx, func(ctx context.Context) error {
		err := s.menuRepo.Update(ctx, m,
			"menu_name", "sort", "status", "parent_id", "update_by",
			"id_path", "icon", "path", "route_name", "no_cache", "component", "visible")
		if err != nil {
			return err
		}
		return s.menuRepo.UpdateIdPath(ctx, oldS, newS)
	})
}

func (s *sysMenuService) UpdateAction(ctx context.Context, req *v1.SysMenuUpdateActionReq) (err error) {
	var m *model.SysMenu
	m, err = s.menuRepo.GetById(ctx, req.MenuId)
	if err != nil {
		return
	}
	m.MenuName = req.MenuName
	m.Sort = req.Sort
	m.Status = req.Status
	m.Permission = req.Permission
	m.ParentId = req.ParentId
	m.UpdateBy = req.AuthId
	if m.MenuType != constant.MenuTypeAction {
		return errcode.ErrBadRequest.New("菜单类型错误")
	}
	if m.ParentId == m.MenuId {
		return errcode.ErrBadRequest.New("父菜单选择错误")
	}

	apiIds := req.ApiIds
	//顶级菜单
	if m.ParentId == 0 {
		return errcode.ErrBadRequest.New("父菜单选择错误")
	}
	var pModel *model.SysMenu
	pModel, err = s.menuRepo.GetById(ctx, m.ParentId)
	if err != nil || pModel.MenuType == constant.MenuTypeAction {
		return errcode.ErrBadRequest.New("父菜单选择错误")
	}
	m.IdPath = fmt.Sprintf("%s%d/", pModel.IdPath, pModel.MenuId)

	//if model.Permission == "" {
	//	return response.ErrInvalidParams.New("权限标识不能为空")
	//}
	if s.menuRepo.ExistsPermission(ctx, m.Permission, m.MenuId) {
		return errcode.ErrBadRequest.New("权限标识已经存在")
	}

	err = s.tm.Transaction(ctx, func(ctx context.Context) error {
		err := s.menuRepo.Update(ctx, m)
		if err != nil {
			return err
		}
		err = s.menuRepo.DeleteMenuApi(ctx, m.MenuId)
		if err != nil {
			return err
		}
		totalId := len(apiIds)
		if totalId > 0 {
			menuApis := make([]*model.SysMenuApi, totalId)
			_apiIds := make([]int64, totalId)
			for i, apiId := range apiIds {
				menuApis[i] = &model.SysMenuApi{
					MenuId: m.MenuId,
					ApiId:  apiId,
				}
				_apiIds[i] = apiId
			}

			//校验apiid
			_apiIds = slices.Unique(_apiIds)
			if len(_apiIds) != totalId {
				return errcode.ErrBadRequest.New("api选择错误")
			}
			return nil
			//apis := make([]*model.SysApi, 0)
			//err = query.Where("api_id in (?)", _apiIds).Find(&apis)
			//if err != nil {
			//	return err
			//}
			//if len(apis) != totalId {
			//	return response.ErrInvalidParams.New("api选择错误")
			//}
			//
			////更新permission
			//roleMenus := make([]*models.SysRoleMenu, 0)
			//err = query.Where("menu_id = ?", model.MenuId).Find(&roleMenus)
			//if err != nil {
			//	return err
			//}
			//err = query.Where("menu_id = ?", model.MenuId).Delete(&models.SysPermission{})
			//if err != nil {
			//	return err
			//}
			//if len(roleMenus) != 0 {
			//	permission := make([]*models.SysPermission, 0)
			//	for _, m := range roleMenus {
			//		for _, a := range apis {
			//			permission = append(permission, &models.SysPermission{
			//				RoleId: m.RoleId,
			//				MenuId: model.MenuId,
			//				ApiKey: a.Key,
			//				Status: model.Status,
			//			})
			//		}
			//	}
			//	err = query.Create(permission)
			//	if err != nil {
			//		return err
			//	}
			//}
			//return query.Create(menuApis)
		}
		return nil
	})
	return
}

func (s *sysMenuService) GetMenuAndPermissionsByUid(ctx context.Context, uid int64) (data v1.SysUserMenus, err error) {
	if uid == 0 {
		return
	}
	if uid == constant.SuperAdmin {

	} else {

	}
	return
}

// genTreeList 根据菜单列表生成树状菜单
func (s *sysMenuService) genTreeList(list []*model.SysMenu, parentId int64) []*model.SysMenu {
	res := make([]*model.SysMenu, 0)
	for _, v := range list {
		if v.ParentId == parentId {
			v.Children = s.genTreeList(list, v.MenuId)
			res = append(res, v)
		}
	}
	return res
}
